home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Interactive Reference Guide / C-C++ Interactive Reference Guide.iso / c_ref / csource4 / 235_01 / ovdir.c < prev    next >
Text File  |  1987-06-18  |  25KB  |  735 lines

  1. /*  030  14-Feb-87  ovdir.c
  2.  
  3.         Copyright (c) 1987 by Blue Sky Software.  All rights reserved.
  4. */
  5.  
  6. #include <stdio.h>
  7. #include "ov.h"
  8. #include "dosfile.h"
  9.  
  10. #define DCOLSIZ 15
  11. #define DCOLS (SCREEN_COLS / DCOLSIZ)
  12.  
  13. #define dr2sr(r) (FIRST_NROW + (r - drbase))
  14. #define dc2sc(c) ((c - dcbase) * DCOLSIZ)
  15.  
  16. #define TO_NONE 0
  17. #define TO_SUBDIR 1
  18. #define TO_SIBLING 2
  19. #define TO_PARENT 3
  20. #define TO_ROOT 4
  21.  
  22. char *strrchr(), *strupr();
  23. struct search_block *nxtfile();
  24.  
  25. struct dir_ent {
  26.    struct dir_ent *subdir;
  27.    struct dir_ent *sibling;
  28.    struct dir_ent *parent;
  29.    struct dir_ent *prev_sib;
  30.    char name[13];
  31.    unsigned char row;
  32.    unsigned char col;
  33. };
  34.  
  35. static last_drive = ' ';
  36. static int drow, dcol, ldrow;
  37. static char dirpath[MAX_PATHLEN+6];
  38. static int drbase, drend, dcbase, dcend;
  39. static struct dir_ent *curdir, *logdir, *findir();
  40. static struct dir_ent root = { NULL, NULL, NULL, NULL, "", 0, 0 };
  41.  
  42. int dir_exit(), dir_login(), dir_mkdir(), dir_rmdir(), dir_new();
  43. extern struct menu_selection top_file_menu[], *top_menu;
  44.  
  45. struct menu_selection top_dir_menu[] = {
  46.    { "Login", "Login (switch) to the highlighted directory", dir_login, NULL },
  47.    { "Mkdir", "Make a subdirectory of the highlighted directory", dir_mkdir, NULL },
  48.    { "New", "Reread and redisplay directory tree", dir_new, NULL },
  49.    { "Rmdir", "Remove (delete) the highlighted directory", dir_rmdir, NULL },
  50.    { "Quit", "Return to file display", dir_exit, top_file_menu },
  51.    { NULL, NULL, NULL, NULL }
  52. };
  53.  
  54. extern struct window cw;
  55. extern unsigned char dir_display, restricted;
  56. char *strchr();
  57.  
  58.  
  59. /******************************************************************************
  60.  **                            D T R E E                                     **
  61.  *****************************************************************************/
  62.  
  63. dtree() {              /* display / work with directory tree */
  64.  
  65.    int drive;
  66.  
  67.    dir_display = TRUE;                 /* dir tree is (will be) displayed */
  68.    restricted = TRUE;                  /* disable some file commands */
  69.  
  70.    /* scan the current disk and create the internal directory tree if it
  71.       hasn't already been built or the user has changed disks */
  72.  
  73.    if ((drive = current_drive()) != last_drive) {  /* has the drive switched? */
  74.  
  75.       if (root.subdir) {                       /* delete current tree */
  76.          del_dtree(root.subdir);               /* if drive switch */
  77.          root.subdir = NULL;
  78.       }
  79.  
  80.       last_drive = drive;
  81.  
  82.       *dirpath = '\0';                         /* scan_dir() starts at */
  83.       strncat(dirpath,cw.dirbuf,3);            /*   drives root dir */
  84.       strcpy(root.name,dirpath);
  85.  
  86.       disp_msg(1,"Scanning disk");             /* takes awhile, tell user */
  87.  
  88.       scan_dir(&root);                         /* build new dir tree */
  89.  
  90.       clr_msg();                               /* done scanning */
  91.  
  92.       drbase = dcbase = 0;                     /* assume dir */
  93.       drend = NAME_ROWS;                         /* will start */
  94.       dcend = DCOLS;                               /* at the root */
  95.  
  96.       curdir = findir();                       /* locate current dir in tree */
  97.  
  98.    } else {            /* don't need to scan the disk */
  99.  
  100.       curdir = findir();               /* point to logged in dir */
  101.       adj_dir_dis();                   /* make sure logged dir will show */
  102.    }
  103.  
  104.    logdir = curdir;                    /* remember the logged dir */
  105.  
  106.    /* now display the current portion of the dir tree */
  107.  
  108.    show_tree();                        /* let user see it */
  109.  
  110.    /* this is a hack, but... if a new drive was scanned, we don't know for
  111.       sure if the curent dir is really displayed because the row/column
  112.       values aren't calculated until it's actully displayed.  If the
  113.       user has more than a screen's worth of directories and he is in one
  114.       of the ones off screen, adjust the offsets and redisplay, sigh... */
  115.  
  116.    if (adj_dir_dis())
  117.       show_tree();
  118.  
  119.    top_menu = top_dir_menu;    /* setup the dir menu as the main menu */
  120. }
  121.  
  122.  
  123. /******************************************************************************
  124.                               D I R _ N E W
  125.  *****************************************************************************/
  126.  
  127. dir_new() {            /* rescan the disk and redisplay the dir tree */
  128.  
  129.    last_drive = ' ';   /* simply force a rescan */
  130.    dtree();            /*   and let dtree() do the work */
  131.    update_vol_stats(); /* in case its a new volume */
  132. }
  133.  
  134.  
  135. /******************************************************************************
  136.  **                       D I R _ E X I T                                    **
  137.  *****************************************************************************/
  138.  
  139. dir_exit() {           /* exit the dir display, return to file display */
  140.  
  141.    dir_display = FALSE;                /* dir tree will not be displayed */
  142.    restricted = FALSE;                 /* allow all file commands */
  143.  
  144.    top_menu = top_file_menu;           /* file menu is main again */
  145.  
  146.    update_header();                    /* always rewrite the entire screen */
  147.    refresh_screen(0);                  /* 'cause there may be > windows */
  148. }
  149.  
  150.  
  151. /******************************************************************************
  152.  **                         S C A N _ D I R                                  **
  153.  *****************************************************************************/
  154.  
  155. scan_dir(dp)           /* scan the specified dir tree for other directories */
  156. struct dir_ent *dp;
  157. {
  158.    int dplen;
  159.    int firsttime = TRUE;
  160.    struct search_block *sbp;
  161.    register struct dir_ent *ndp, *ldp = NULL;
  162.  
  163.    /* build the pathname of the dir to scan */
  164.  
  165.    dplen = strlen(dirpath);                    /* remember callers length */
  166.    if (strcmp(dp->name+2,"\\") != 0) {         /* special case if root dir */
  167.       strcat(dirpath,dp->name);                /* add name of dir to scan */
  168.       strcat(dirpath,"\\");
  169.    }
  170.    strcat(dirpath,"*.*");                      /* add wildcard string */
  171.  
  172.    /* scan all files in directory looking for subdirectories.  When a
  173.       subdirectory is found, add it to the dir_ent tree.  Note, the . and
  174.       .. directory entries are ignored. */
  175.  
  176.    while (sbp = nxtfile(dirpath,0x16,&firsttime))
  177.       if (sbp->attrib & DIR && *sbp->fn != '.') {
  178.  
  179.          /* found a subdir we want, build a struct dir_ent for it */
  180.          ndp = (struct dir_ent *) Malloc(sizeof(struct dir_ent));
  181.          strcpy(ndp->name,sbp->fn);
  182.          ndp->subdir = NULL;
  183.          ndp->sibling = NULL;
  184.          ndp->parent = dp;
  185.          ndp->prev_sib = ldp;
  186.  
  187.          /* now link it to the dir_ent tree either as a subdir of the
  188.             parent (1st one only) or a sibling of the last one */
  189.  
  190.          if (ldp)
  191.             ldp->sibling = ndp;        /* not 1st, is a sibling */
  192.          else
  193.             dp->subdir = ndp;          /* 1st one, subdir of parent */
  194.  
  195.          ldp = ndp;                    /* new one is now the last one */
  196.       }
  197.  
  198.    /* if any subdirectories were found, scan 'em.  This isn't done
  199.       earlier so the file search isn't complicated by the directory
  200.       switches. */
  201.  
  202.    if (ldp) {                            /* NULL if no sub's found */
  203.       dirpath[strlen(dirpath)-3] = '\0'; /* remove *.* for next level */
  204.       ldp = dp->subdir;                  /* start with the first one */
  205.       do {
  206.          scan_dir(ldp);                /* call ourselves to scan this subtree */
  207.       } while (ldp = ldp->sibling);    /* do all the subs found */
  208.    }
  209.  
  210.    dirpath[dplen] = '\0';              /* restore dir pathname for caller */
  211. }
  212.  
  213.  
  214. /******************************************************************************
  215.  **                           D E L _ D T R E E                              **
  216.  *****************************************************************************/
  217.  
  218. del_dtree(dp)          /* purge the current in memory dir tree structure */
  219. register struct dir_ent *dp;
  220. {
  221.  
  222.    register struct dir_ent *ndp;
  223.  
  224.    /* delete this subdirectory ENTRY and all sibling ENTRIES (not the
  225.       actual directories) */
  226.  
  227.    do {
  228.  
  229.       if (dp->subdir)            /* if it has a subdir, make a recursive call */
  230.          del_dtree(dp->subdir);  /* to delete the substructure */
  231.  
  232.       ndp = dp->sibling;         /* get address of any sibling */
  233.  
  234.       free((char *)dp);          /* free the dir_ent space itself */
  235.  
  236.    } while (dp = ndp);           /* do until no more siblings */
  237.  
  238. }
  239.  
  240.  
  241. /******************************************************************************
  242.  **                        S H O W _ T R E E                                 **
  243.  *****************************************************************************/
  244.  
  245. static int
  246. show_tree() {          /* setup and display the dir tree */
  247.  
  248.    drow = 0;                           /* disp_dtree() needs these set */
  249.    ldrow = dcol = -1;
  250.    disp_dtree(&root);                  /* redisplay new part of tree */
  251. }
  252.  
  253.  
  254. /******************************************************************************
  255.  **                         D I S P _ D T R E E                              **
  256.  *****************************************************************************/
  257.  
  258. disp_dtree(dp)                 /* display the directory tree */
  259. register struct dir_ent *dp;
  260. {
  261.    int next_row;
  262.  
  263.    ++dcol;             /* each invocation is another directory level */
  264.  
  265.    /* display this subdirectory and all its siblings */
  266.  
  267.    do {
  268.  
  269.       /* if drow != ldrow, then this is the first entry on this display
  270.          row, clear the line to remove any old junk that might be there */
  271.  
  272.       if (drow != ldrow && drow >= drbase && drow < drend) {
  273.          gotorc(dr2sr(drow),dc2sc(dcbase));
  274.          clr_eol();
  275.          ldrow = drow;
  276.       }
  277.  
  278.       /* mark the dir_ent's with the logical display row/col so that
  279.          dir_move() has an easy time displaying the entries */
  280.  
  281.       dp->row = drow;
  282.       dp->col = dcol;
  283.  
  284.       /* only display a dir  entry if it falls within the boundries, figure
  285.          out if this one does and display the name if so - the dir under
  286.          the pointer is highlighted, the logged dir is 'tagged' all others
  287.          are displayed 'normal' */
  288.  
  289.       if (dir_on_screen(drow,dcol))
  290.          disp_dir_name(dp,dp == curdir ? DIS_HIGH :
  291.                        (dp == logdir ? DIS_TAGD : DIS_NORM));
  292.  
  293.       /* if this dir has a subdir, process that now */
  294.  
  295.       if (dp->subdir) {
  296.  
  297.          next_row = drow + 1;          /* remember where next sibling goes */
  298.  
  299.          disp_dtree(dp->subdir);       /* display the subdir tree */
  300.  
  301.          /* if the current dir has more siblings (more names to display at
  302.             this level) and the subdir tree changed the next display row,
  303.             output bar spacers to get down to the sibling */
  304.  
  305.          if (drow > next_row && dp->sibling)
  306.             for (; next_row < drow; next_row++)
  307.                if (dir_on_screen(next_row,dcol))
  308.                   disp_char_at(0xb3,dr2sr(next_row),dc2sc(dcol));
  309.  
  310.       } else                           /* has no subdir */
  311.          ++drow;                       /* thats all for this line, advance */
  312.  
  313.    } while (dp = dp->sibling);         /* do all siblings at this level */
  314.  
  315.    --dcol;                             /* this level is done */
  316.  
  317.    /* if the root level is done (dcol < 0 - meaning there are no more dir
  318.       entries to be displayed) and we didn't reach the bottom of the display
  319.       area, clear out the rest of the lines to remove any garbage that
  320.       might be there */
  321.  
  322.    if (dcol < 0 && drow < NAME_ROWS)
  323.       for (; drow < NAME_ROWS; drow++) {
  324.          gotorc(dr2sr(drow),dc2sc(dcbase));
  325.          clr_eol();
  326.       }
  327.  
  328. }
  329.  
  330.  
  331. /******************************************************************************
  332.  **                    D I S P _ D I R _ N A M E                             **
  333.  *****************************************************************************/
  334.  
  335. disp_dir_name(dp,va)   /* display a single dir name */
  336. register struct dir_ent *dp;
  337. int va;
  338. {
  339.    gotorc(dr2sr(dp->row),dc2sc(dp->col));      /* move to display location */
  340.  
  341.    /* display the leadin bar to the dir name, it depends on whether
  342.       this is the root, the 1st subdir, the last sibling, and if any
  343.       siblings follow */
  344.  
  345.    if (dp->col) {                                 /* root dir? */
  346.       if (dp->prev_sib == NULL)                   /* 1st subdir? */
  347.          disp_char((dp->sibling) ? 0xc2 : 0xc4);  /* siblings follow? */
  348.       else
  349.          disp_char((dp->sibling) ? 0xc3 : 0xc0);
  350.    } else
  351.       disp_char(' ');                          /* root - no leadin */
  352.  
  353.    if (va != DIS_NORM)                         /* setup highlight if needed */
  354.       setvattrib(va);
  355.  
  356.    disp_char(' ');
  357.    disp_str(dp->name);                         /* display the name */
  358.    disp_char(' ');
  359.  
  360.    /* draw bar to subdir or blank fill name */
  361.  
  362.    disp_rep(dp->subdir ? 0xc4 : ' ',DCOLSIZ - strlen(dp->name) - 3);
  363.  
  364.    if (va != DIS_NORM)         /* restore normal attribute if changed */
  365.       setvattrib(DIS_NORM);
  366. }
  367.  
  368.  
  369. /******************************************************************************
  370.  **                       D I R _ M O V E                                    **
  371.  *****************************************************************************/
  372.  
  373. dir_move(move_cmd)     /* move the directory pointer around */
  374. int move_cmd;
  375. {
  376.    int moved = TO_NONE;
  377.    int redisplayed = FALSE;
  378.    register struct dir_ent *last_dir, *cdp;
  379.  
  380.    last_dir = cdp = curdir;    /* remember where we are/were and fast ptr */
  381.  
  382.    switch (move_cmd) {
  383.  
  384.       case RIGHT:
  385.          if (cdp->subdir) {
  386.             cdp = cdp->subdir;
  387.             moved = TO_SUBDIR;
  388.          } else
  389.             if (cdp->sibling) {
  390.                cdp = cdp->sibling;
  391.                moved = TO_SIBLING;
  392.             }
  393.             /* stuff about parents goes here */
  394.          break;
  395.  
  396.       case LEFT:
  397.          if (cdp->prev_sib) {
  398.             cdp = cdp->prev_sib;
  399.             moved = TO_SIBLING;
  400.          } else
  401.             if (cdp->parent) {
  402.                cdp = cdp->parent;
  403.                moved = TO_PARENT;
  404.             }
  405.          break;
  406.  
  407.       case UP:
  408.          if (cdp->prev_sib) {
  409.             cdp = cdp->prev_sib;
  410.             moved = TO_SIBLING;
  411.          }
  412.          break;
  413.  
  414.       case DOWN:
  415.          if (cdp->sibling) {
  416.             cdp = cdp->sibling;
  417.             moved = TO_SIBLING;
  418.          }
  419.          break;
  420.  
  421.       case HOME:
  422.          cdp = &root;
  423.          moved = TO_ROOT;
  424.          break;
  425.  
  426.       case GOPAR:
  427.          if (cdp->parent) {
  428.             cdp = cdp->parent;
  429.             moved = TO_PARENT;
  430.          }
  431.       break;
  432.  
  433.    }
  434.  
  435.    curdir = cdp;           /* assign it */
  436.  
  437.    /* adjust and redisplay the pathname as the user moves the dir pointer */
  438.  
  439.    if (moved != TO_NONE)
  440.       update_dirpath(moved);
  441.  
  442.    /* display a different section of dir tree if current isn't displayed */
  443.  
  444.    if (adj_dir_dis()) {                /* is adjustment needed? */
  445.       show_tree();                     /* display the tree */
  446.       redisplayed = TRUE;              /* save a disp_dir_name() call */
  447.    }
  448.  
  449.    /* deselect the last dir if the dir pointer moved and the last one
  450.       is still on the screen and the entire tree wasn't redisplayed */
  451.  
  452.    if (!redisplayed && last_dir != curdir &&
  453.        dir_on_screen(last_dir->row,last_dir->col))
  454.       disp_dir_name(last_dir,last_dir == logdir ? DIS_TAGD : DIS_NORM);
  455.  
  456.    /* select (highlight) a new dir entry if pointer moved and the tree
  457.       wasn't redisplayed */
  458.  
  459.    if (last_dir != curdir && !redisplayed) {
  460.       disp_dir_name(curdir,DIS_HIGH);
  461.    }
  462. }
  463.  
  464.  
  465. /******************************************************************************
  466.  **                       D I R _ L O G I N                                  **
  467.  *****************************************************************************/
  468.  
  469. dir_login() {          /* login the dir selected by the dir pointer */
  470.  
  471.    /* switch to selected dir, if can't switch, user may have changed
  472.       disks, force a scan of the disk for dirs */
  473.  
  474.    if (switch_dir(dirpath) != 0)       /* switch to the selected dir */
  475.       last_drive = ' ';
  476.  
  477.    dir_exit();                         /* exit the dir display mode */
  478.  
  479. }
  480.  
  481.  
  482. /******************************************************************************
  483.  **                       D I R _ R M D I R                                  **
  484.  *****************************************************************************/
  485.  
  486. dir_rmdir() {          /* remove the dir selected by the dir pointer */
  487.  
  488.    int moveto;
  489.    register struct dir_ent *cdp;
  490.  
  491.    cdp = curdir;               /* try to reduce code size */
  492.  
  493.    /* don't even let user try to delete the root or current directories */
  494.  
  495.    if (cdp->col == 0 || strcmp(dirpath,cw.dirbuf) == 0)
  496.       show_error(0,4,3,"You can't delete the ",(cdp->col == 0) ? "root" :
  497.                 "current"," directory!");
  498.  
  499.    /* use DOS to acutally remove the directory */
  500.  
  501.    if (rmdir(dirpath) != 0)
  502.       show_error(1,4,1,"Unable to remove dir: ");
  503.  
  504.    /* Okay, the dir is gone, now remove it from the dir tree */
  505.  
  506.    if (cdp->prev_sib)                                  /* make prev sib -> */
  507.       cdp->prev_sib->sibling = cdp->sibling;           /* next sib */
  508.  
  509.    if (cdp->sibling) {                                 /* next sib -> */
  510.       cdp->sibling->prev_sib = cdp->prev_sib;          /* prev sib && */
  511.       if (cdp->parent->subdir == cdp)                  /* parent ->   */
  512.          cdp->parent->subdir = cdp->sibling;           /* next sib    */
  513.    }
  514.  
  515.    if (cdp->prev_sib == NULL && cdp->sibling == NULL)  /* parent has no */
  516.       cdp->parent->subdir = NULL;                      /* more sub's */
  517.  
  518.    /* when deleting a subdirectory, try to make a sibling the current dir,
  519.       if none, go back to parent */
  520.  
  521.    if (cdp->sibling) {
  522.       curdir = cdp->sibling;
  523.       moveto = TO_SIBLING;
  524.    } else
  525.       if (cdp->prev_sib) {
  526.          curdir = cdp->prev_sib;
  527.          moveto = TO_SIBLING;
  528.       } else {
  529.          curdir = cdp->parent;
  530.          moveto = TO_PARENT;
  531.       }
  532.  
  533.    update_vol_stats();                 /* should be more free space now */
  534.  
  535.    update_dirpath(moveto);             /* show user what the dir pathname is */
  536.  
  537.    free((char *)cdp);                  /* release mem used by the dir entry */
  538.  
  539.    /* redisplay the tree to adjust the display and reassign row, col values */
  540.  
  541.    adj_dir_dis();
  542.    show_tree();
  543. }
  544.  
  545.  
  546. /******************************************************************************
  547.  **                       D I R _ M K D I R                                  **
  548.  *****************************************************************************/
  549.  
  550. dir_mkdir() {          /* make a subdirectory in the selected dir */
  551.  
  552.    int rc;
  553.    char *name, *dirend;
  554.    register struct dir_ent *ndp, *ldp;
  555.  
  556.    /* ask user what to call the new directory */
  557.  
  558.    name = strupr(prompt("","Enter the new subdirectory name: ",NULL,0,12));
  559.    if (strlen(name) == 0)
  560.       return;
  561.  
  562.    /* update dirpath to include the users new name */
  563.  
  564.    dirend = dirpath + strlen(dirpath); /* remember current dirpath end */
  565.    if (*(dirend-1) != '\\')
  566.       strcat(dirend,"\\");
  567.    strcat(dirend,name);                /* add users dir name */
  568.  
  569.    /* use DOS to acutally make the directory */
  570.  
  571.    rc = mkdir(dirpath);                /* create it */
  572.  
  573.    *dirend = '\0';                     /* fixup dirpath */
  574.  
  575.    if (rc != 0)
  576.       show_error(1,4,1,"Unable to make dir: ");
  577.  
  578.    /* Okay, the dir is created, now make a dir_ent and add it to the dir tree */
  579.  
  580.    ndp = (struct dir_ent *) Malloc(sizeof(struct dir_ent));
  581.    strcpy(ndp->name,name);
  582.    ndp->subdir = NULL;
  583.    ndp->sibling = NULL;
  584.    ndp->parent = curdir;
  585.  
  586.    if (ldp = curdir->subdir) {                 /* any sibs to new dir? */
  587.       while (ldp->sibling)                     /* find end of sib list */
  588.          ldp = ldp->sibling;
  589.       ndp->prev_sib = ldp;                     /* new one is last */
  590.       ldp->sibling = ndp;
  591.    } else {
  592.       ndp->prev_sib = NULL;                    /* no sibs */
  593.       curdir->subdir = ndp;                    /* parent now has subdir */
  594.    }
  595.  
  596.    update_vol_stats();                 /* less free space now */
  597.  
  598.    /* redisplay the tree to adjust the display and reassign row, col values */
  599.  
  600.    show_tree();
  601. }
  602.  
  603.  
  604. /******************************************************************************
  605.  **                    U P D A T E _ D I R P A T H                           **
  606.  *****************************************************************************/
  607.  
  608. static int
  609. update_dirpath(moved)          /* update & redisplay dir path */
  610. int moved;
  611. {
  612.    char *cp;
  613.  
  614.    switch (moved) {
  615.  
  616.       case TO_SUBDIR:                  /* moved to a subdir */
  617.          if (curdir->col != 1)         /* append a \ if parent wasn't root */
  618.             strcat(dirpath,"\\");
  619.          strcat(dirpath,curdir->name); /* append the subdirectory name */
  620.          break;
  621.  
  622.       case TO_SIBLING:                 /* moved to a sibling */
  623.          *(strrchr(dirpath,'\\')+1) = '\0';
  624.          strcat(dirpath,curdir->name);
  625.          break;
  626.  
  627.       case TO_PARENT:                  /* moved to parent */
  628.          cp = strrchr(dirpath,'\\');
  629.          if (curdir->col == 0)
  630.             ++cp;
  631.          *cp = '\0';
  632.          break;
  633.  
  634.       case TO_ROOT:                    /* moved to the root */
  635.         dirpath[3] = '\0';
  636.         break;
  637.    }
  638.  
  639.    gotorc(VOL_ROW,PATH_COL+1);
  640.    out_str(dirpath,65,' ');
  641. }
  642.  
  643.  
  644. /*****************************************************************************
  645.                           A D J _ D I R _ D I S
  646.  *****************************************************************************/
  647.  
  648. adj_dir_dis() {        /* make sure current dir ent will be on screen */
  649.  
  650.    register int r, c;
  651.  
  652.    /* adjust bounds and redisplay dir tree if the current entry is not
  653.       displayed */
  654.  
  655.    r = curdir->row;  c = curdir->col;  /* cutout a level of indirection */
  656.  
  657.    if (!dir_on_screen(r,c)) {
  658.  
  659.       if (r >= drend)                  /* current below display? */
  660.          drbase = r - NAME_ROWS + 1;
  661.       else
  662.          if (r < drbase)               /* current above display? */
  663.             drbase = r;
  664.  
  665.       if (c >= dcend)                  /* current right of display? */
  666.          dcbase = c - DCOLS + 1;
  667.       else
  668.          if (c < dcbase)               /* current left of display? */
  669.             dcbase = c;
  670.  
  671.       drend = drbase + NAME_ROWS;      /* reset display end markers */
  672.       dcend = dcbase + DCOLS;
  673.  
  674.       return(1);                       /* tell caller to redisplay */
  675.    }
  676.  
  677.    return(0);                          /* no adjustment needed */
  678. }
  679.  
  680.  
  681. /*****************************************************************************
  682.                              F I N D I R
  683.  *****************************************************************************/
  684.  
  685. static struct dir_ent *
  686. findir() {             /* find the current dir_ent */
  687.  
  688.    register char *lcp;
  689.    char *cp = cw.dirbuf+3;
  690.    char dirname[MAX_NAMELEN+2];
  691.    register struct dir_ent *dp = &root;
  692.  
  693.    *dirpath = '\0';
  694.    strncat(dirpath,cw.dirbuf,3);       /* roots better be the same */
  695.  
  696.    while (strcmp(dirpath,cw.dirbuf) != 0) {    /* have we found it yet? */
  697.  
  698.       /* haven't found it yet, go down another dir level, also do some
  699.          protective error checks, I don't feel real secure 'bout this yet */
  700.  
  701.       if (dp == NULL || (dp = dp->subdir) == NULL || (lcp = cp) == NULL)
  702.          return(&root);                        /* shouldn't happen, but... */
  703.  
  704.       if (cp = strchr(cp+1,'\\')) {            /* isolate the next dir level */
  705.          *dirname = '\0';                      /*   in cw.dirbuf */
  706.          strncat(dirname,lcp,cp-lcp);
  707.       } else
  708.          strcpy(dirname,lcp);                  /* this must be the last level */
  709.  
  710.       strcat(dirpath,dirname);                 /* add dir name to full path */
  711.  
  712.       if (*(lcp = dirname) == '\\')            /* 1st doesn't have leading \ */
  713.          lcp++;                                /*   others do */
  714.  
  715.       /* check all siblings at this level until we find it (or run out?) */
  716.  
  717.       while (dp && strcmp(lcp,dp->name) != 0)
  718.          dp = dp->sibling;
  719.    }
  720.  
  721.    return(dp);                 /* this should be the one */
  722. }
  723.  
  724.  
  725. /*****************************************************************************
  726.                         D I R _ O N _ S C R E E N
  727.  *****************************************************************************/
  728.  
  729. static int
  730. dir_on_screen(r,c)     /* determine if dir name is displayed */
  731. register int r, c;
  732. {
  733.    return(r >= drbase && r < drend && c >= dcbase && c < dcend);
  734. }
  735.